// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


/**
 * @fileoverview For use as a Google Apps Scripts.  Reads Inputs and
 * Templates from two sheets and runs each input through each
 * template.  Inserts a new sheet to display generated output.
 */

goog.provide('ads_mult.SpreadsheetReader');

goog.require('ads_mult.common');


/**
 * Class to read inputs and campaigns from spreadsheet into Objects
 * @param {Spreadsheet} spreadsheet Spreadsheet to read from.
 * @constructor
 */
ads_mult.SpreadsheetReader = function(spreadsheet) {
  this.spreadsheet = spreadsheet;
};


/**
 * For every row in data, generates an object that contains the data
 * Names of object fields are defined in keys.
 * @param {Array.<Array.<string>>} data A 2D array of strings.
 * @param {Array.<string>} keys Array of strings that define the property
 *     names for the objects getting created.
 * @param {boolean} fillBlanks Whether to fill in blank values with previous
 *     row's, or to just skip and leave blank.
 * @return {Array.<Object.<string,string>>} An Array of objects, where each
 *     field is a column header.
 * @private
 */
ads_mult.SpreadsheetReader.getObjects_ = function(data, keys, fillBlanks) {
  var objects = [];

  // keep a record of the last complete row
  // this may be piecemeal, with values from multiple actual rows
  var lastObject = {};

  // for each row, create an object
  for (var i = 0; i < data.length; ++i) {
    var object = {};
    var hasData = false;
    // each column
    for (var j = 0; j < data[i].length; ++j) {
      var cellData = (ads_mult.common.isCellEmpty(data[i][j]) && fillBlanks) ?
          lastObject[keys[j]] :
          data[i][j];
      if (!cellData || ads_mult.common.isCellEmpty(cellData)) {
        continue;
      }
      object[keys[j]] = cellData;
      lastObject[keys[j]] = cellData;
      hasData = true;
    }
    if (hasData) {
      objects.push(object);
    }
  }
  return objects;
};


/**
 * Converts sheet of data, row by row, into an Array of objects
 * Finds relevant range to convert.
 * @param {Sheet} sheet Worksheet to grab data from.
 * @param {boolean} doNorm Whether to normalize the column headers or not.
 *     This is usually for Templates, not Inputs.
 * @param {boolean} fillBlanks Whether to fill in blank values with previous
 *     row's, or to just skip and leave blank.
 * @return {Array.<Object>} Array of objects, where each field is a column
 *     header.
 * @private
 */
ads_mult.SpreadsheetReader.getRowData_ = function(sheet, doNorm, fillBlanks) {
  var numRows = sheet.getLastRow();
  var numCols = sheet.getLastColumn();
  // assumes first row is header
  var headersRange = sheet.getRange(1, 1, 1, numCols);
  var headers = headersRange.getValues()[0];
  headers = doNorm ? ads_mult.common.normalizeHeaders(headers) : headers;

  // get numRows - 1 rows, b/c first row was headers
  var range = sheet.getRange(2, 1, numRows - 1, numCols);
  return ads_mult.SpreadsheetReader.getObjects_(
      range.getValues(), headers, fillBlanks);
};


/**
 * Reads inputs from Input Sheet.
 * @param {string} sheetName Name of sheet that contains Inputs on it.
 * @return {Array.<Object>} Array of objects, where each row of input
 *     is an object.
 */
ads_mult.SpreadsheetReader.prototype.getInputs = function(sheetName) {
  var sheet = this.spreadsheet.getSheetByName(sheetName);
  return ads_mult.SpreadsheetReader.getRowData_(sheet, false, true);
};


/**
 * Reads templates from Template Sheet.
 * @param {string} sheetName Name of sheet that contains Templates on it.
 * @return {Array.<Object>} Array of objects, where each row of input
 *     is an object.
 */
ads_mult.SpreadsheetReader.prototype.getTemplates = function(sheetName) {
  var sheet = this.spreadsheet.getSheetByName(sheetName);
  return ads_mult.SpreadsheetReader.getRowData_(sheet, true, true);
};


/**
 * Reads character limits from sheet.
 * @param {string} sheetName Name of the Sheet to read from.
 * @return {Object} object, with character limits for each column name.
 */
ads_mult.SpreadsheetReader.prototype.getLimits = function(sheetName) {
  var sheet = this.spreadsheet.getSheetByName(sheetName);
  var data = ads_mult.SpreadsheetReader.getRowData_(sheet, true, false)[0];
  for (var lim in data) {
    data[lim] = parseInt(data[lim], 10);
  }
  return data;
};


/**
 * Reads headers from any sheet.
 * @param {string} sheetName Name of sheet to grab headers from.
 * @return {Array.<string>} Array of strings, where each string is a column
 *     header from sheet.
 */
ads_mult.SpreadsheetReader.prototype.getHeaders = function(sheetName) {
  var sheet = this.spreadsheet.getSheetByName(sheetName);
  var numCols = sheet.getLastColumn();
  // assumes first row is header
  return sheet.getRange(1, 1, 1, numCols).getValues()[0];
};
